package com.mad.game.backend;

import java.util.Map;
import java.util.Observable;

import com.mad.game.system.EGameState;
import com.mad.game.system.GameSystem;
import com.mad.game.system.Vector2;
import com.mad.game.view.ViewManager;
import com.mad.game.view.level.Level;
import com.mad.game.view.models.GameModel;
import com.mad.game.view.models.ModelPool;

public class GameDemo extends Observable {

	public static void main(String[] args) {
		GameDemo.start();
	}

	public static final String TITLE = "Game Demo [ version 0.1 Alpha ]";

	private static GameDemo gameInstance = null;

	static void start() {
		if (gameInstance == null)
			gameInstance = new GameDemo();
	}

	public static GameDemo getGameInstance() {
		return gameInstance;
	}

	private ViewManager viewManager;
	private EGameState gameState;
	private Level level;
	private GameThread gameThread;

	public EGameState getGameState() {
		return gameState;
	}

	public void setGameState(EGameState gameState) {
		this.gameState = gameState;
		this.setChanged();
		this.notifyObservers(gameState);
	}

	public boolean isExitRequested() {
		return this.gameState.equals(EGameState.EXIT_REQUESTED);
	}

	public void exitApplication() {
		this.setGameState(EGameState.EXIT_REQUESTED);
	}

	public void startGame() {
		this.setGameState(EGameState.GAME);
		this.level = new Level();
		this.gameThread = new GameThread();
		this.gameThread.start();
	}

	public void leaveGame() {
		this.level = null;
		this.enterMainMenu();
	}

	public void enterMainMenu() {
		this.setGameState(EGameState.MAIN_MENU);
	}

	public boolean isInGame() {
		return this.gameState.equals(EGameState.GAME);
	}

	public ModelPool getModelPool() {
		return this.level.getModelPool();
	}

	private GameDemo() {
		this.viewManager = new ViewManager();
		this.addObserver(this.viewManager);
		this.enterMainMenu();
	}

	private boolean canUpdateGameLoop() {
		return this.level != null && this.level.getModelPool() != null;
	}

	private final class GameThread extends Thread {
		public void run() {
			while (!isExitRequested() && isInGame()) {
				if (canUpdateGameLoop()) {
					try {
						level.update();
						viewManager.updateGraphics();
						Thread.sleep(GameSystem.TARGET_DELTA_UPDATE_TIME);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	public Map<String, GameModel> getModels() {
		return level.getModels();
	}

	public void spawnPlayer() {
		level.spawnPlayer();
	}

	public GameModel getModelById(String modelID) {
		return level.getModelById(modelID);
	}

	public boolean doesModelCollide_inMovement(GameModel model) {
		return level.doesModelCollide_inMovement(model) != null;
	}

	 public boolean doesModelCollide(GameModel model) {
		 return level.doesModelCollide(model) != null ; 
	 }

	public void moveEntityLeft(String id) {
		level.moveEntityLeft(id);
	}

	public void addNewModel(String id, GameModel model) {
		level.addNewModel(id, model);
	}

	public void removeModel(String id) {
		level.removeModel(id);
	}

	public void removeModel(GameModel model) {
		level.removeModel(model);
	}

	public void moveEntityRight(String id) {
		level.moveEntityRight(id);
	}

	public void jumpEntityInMove(String id) {
		level.jumpEntityInMove(id);
	}

	public void jumpEntityStraightUp(String id) {
		level.jumpEntityStraightUp(id);
	}

	public boolean doesEntityJump(String id) {
		return level.doesEntityJump(id);
	}

	public void entityShoot(String id) {
		level.entityShoot(id);
	}
	
	public void movePlayerLeft() {
		this.moveEntityLeft(ModelPool.PLAYER);
	}

	public void movePlayerRight() {
		this.moveEntityRight(ModelPool.PLAYER);
	}

	public boolean doesPlayerExist() {
		return this.level.getModelById(ModelPool.PLAYER) != null;
	}

	public boolean doesPlayerJump() {
		return this.doesEntityJump(ModelPool.PLAYER);
	}

	public void jumpPlayerStraightUp() {
		this.jumpEntityStraightUp(ModelPool.PLAYER);
	}

	public void playerShoot() {
		level.entityShoot(ModelPool.PLAYER);
	}
	
	public void moveCameraLeft() {
		level.moveCameraLeft();
	}

	public void moveCameraRight() {
		level.moveCameraRight();
	}

	public boolean doesCameraMove(){
		return level.doesCameraMove();
	}
	
	public boolean canMoveCamera() {
		return level.canMoveCamera();
	}

	public void setCanMoveCamera(boolean canMoveCamera) {
		level.setCanMoveCamera(canMoveCamera);
	}

	public Vector2 getCameraPosition() {
		return level.getCameraPosition();
	}

	public boolean isLevelPaused() {
		return level.isPaused();
	}

	public void pauseLevel() {
		level.setPaused(true);
	}

	public void continueLevel() {
		level.setPaused(false);
	}

}
